﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.Caching;
using System.Reflection;
using System.Web;
using System.IO;
using System.Web.UI.WebControls;

namespace YhmOA.Common
{
    #region BasePage类的预处理类
    /// <summary>
    /// BasePage类的预处理类
    /// </summary>
    [Serializable]
    internal class Pretreatment : IRequiresSessionState
    {
        #region 当前页面
        /// <summary>
        /// 当前页面
        /// </summary>
        private Page page;
        #endregion

        #region 页面输出类型
        /// <summary>
        /// 页面输出类型
        /// </summary>
        private ResponseType responseType;
        /// <summary>
        /// 页面输出类型
        /// </summary>
        public ResponseType ResponseType
        {
            get { return responseType; }
            set { responseType = value; }
        }
        #endregion

        #region 返回客户端的服务端消息集合
        /// <summary>
        /// 返回客户端的服务端消息集合
        /// </summary>
        private ServerMessageList serverMessageList;
        /// <summary>
        /// 返回客户端的服务端消息集合
        /// </summary>
        public ServerMessageList ServerMessageList
        {
            get { return serverMessageList; }
            set { serverMessageList = value; }
        }
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="page">当前页面类</param>
        /// <param name="responseType">当前页面类的输出类型</param>
        public Pretreatment(Page page, ResponseType responseType)
        {
            this.serverMessageList = new ServerMessageList();
            this.responseType = responseType;
            this.page = page;
        }
        #endregion

        #region 向客户端注册函数的计数器
        /// <summary>
        /// 向客户端注册函数的计数器
        /// </summary>
        private int clientScriptCount = 0;
        #endregion

        #region 向客户端注册标记AjaxMethodAttribute数据的方法
        /// <summary>
        /// 向客户端注册标记AjaxMethodAttribute数据的方法
        /// </summary>
        public void RegisterFunctionToClient()
        {
            if (!this.page.IsPostBack)
            {
                string GetLPLClientScript = this.page.Request["GetLPLClientScript"];
                if (GetLPLClientScript != null && GetLPLClientScript == "GetLPLClientScript")
                {
                    foreach (MethodInfo info in this.page.GetType().GetMethods())
                    {
                        foreach (object item in info.GetCustomAttributes(true))
                        {
                            if (item.GetType().ToString() == typeof(AjaxMethodAttribute).ToString())
                            {
                                this.RegisterFunctionToClient(info.Name);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 将指定的方法注册到客户端
        /// </summary>
        /// <param name="methodName">指定的方法名</param>
        private void RegisterFunctionToClient(string methodName)
        {
            RegisterFunctionToClient(methodName, this.page.GetType().GetMethod(methodName).GetParameters().Length);
        }

        /// <summary>
        /// 将指定的方法注册到客户端
        /// </summary>
        /// <param name="methodName">指定的方法名</param>
        /// <param name="parametersCount">方法参数的个数</param>
        private void RegisterFunctionToClient(string methodName, int parametersCount)
        {
            StringBuilder builder = new StringBuilder();
            if (this.GetCache("____client__" + this.GetPageGuid()) != null)
                builder.AppendLine(this.GetCache("____client__" + this.GetPageGuid()).ToString());
            StringBuilder sb = new StringBuilder();
            string parameters = "";
            for (int i = 0; i < parametersCount; i++)
            {
                parameters += "parameter" + i + ",";
            }
            sb.AppendLine("function " + methodName + "(" + parameters + "callbackfun){");
            sb.AppendLine("\tvar parameter = ____PretreatmentParameters__" + methodName + "(" + parameters + parametersCount + ");");
            sb.AppendLine("\tif (callbackfun != null)");
            sb.AppendLine("\t\treturn ____lipuliang.callServer('" + methodName + "', parameter, true, callbackfun);");
            sb.AppendLine("\telse");
            sb.AppendLine("\t\treturn ____lipuliang.callServer('" + methodName + "', parameter, false, null);");
            sb.AppendLine("}");
            sb.AppendLine("function ____PretreatmentParameters__" + methodName + "(" + parameters + "parametersCount){");
            sb.AppendLine("\tif (!parametersCount)");
            sb.AppendLine("\t\treturn null;");
            sb.AppendLine("\tvar result = '';");
            sb.AppendLine("\tfor (var i = 0; i < parametersCount; i++) {");
            sb.AppendLine("\t\tresult += ____lipuliang.encode(eval('parameter'+i))+',';");
            sb.AppendLine("\t}");
            sb.AppendLine("\tif (result.length > 0) ");
            sb.AppendLine("\t\tresult = result.substr(0, result.length - 1);");
            sb.AppendLine("\treturn result;");
            sb.AppendLine("}");
            if (builder.ToString().IndexOf(sb.ToString()) < 0)
            {
                builder.Append(sb);
            }
            this.SetCache("____client__" + this.GetPageGuid(), builder);
        }
        #endregion

        #region 执行客户端脚本
        /// <summary>
        /// 执行客户端脚本
        /// </summary>
        /// <param name="script">要执行的脚本</param>
        public void ExecClientScript(string script)
        {
            string content = "____lipuliang.ServerCallFunction = function(){try {" + script + "}catch (ex) {alert(\"Error:\" + ex);}};____lipuliang.ServerCallFunction();";
            if (this.IsLplPostBack)
            {
                this.serverMessageList.Add(new ServerMessage(ServerMessageType.Script, content));
            }
            else
            {
                this.RegisterScriptToClient("<script type=\"text/javascript\">"+content+"</script>");
            }
        }
        #endregion

        #region 向客户端弹出选择窗口
        /// <summary>
        /// 向客户端弹出选择窗口
        /// </summary>
        /// <param name="text">提示框中显示的文字</param>
        /// <param name="okScript">选择是的时候执行的脚本</param>
        /// <param name="noScript">选择否的时候执行的脚本</param>
        public void Confirm(string text, string okScript, string noScript)
        {
            this.ExecClientScript("if(confirm(\"" + this.FilterString(text) + "\")){" + this.FilterString(okScript) + "}else{" + this.FilterString(noScript) + "}");
        }
        #endregion

        #region 向客户端弹出选择窗口
        /// <summary>
        /// 向客户端弹出选择窗口
        /// </summary>
        /// <param name="text">提示框中显示的文字</param>
        /// <param name="okScript">选择是的时候执行的脚本</param>
        public void Confirm(string text, string okScript)
        {
            this.ExecClientScript("if(confirm(\"" + this.FilterString(text) + "\")){" + this.FilterString(okScript) + "}");
        }
        #endregion

        #region 设置控件获取焦点
        /// <summary>
        /// 设置控件获取焦点
        /// </summary>
        /// <param name="clientId">要获取焦点的控件ID</param>
        public void Focus(string clientId)
        {
            this.ExecClientScript("document.getElementById(\"" + clientId + "\").focus();");
        }
        #endregion

        #region 设置控件获取焦点并将其文本选中
        /// <summary>
        /// 设置控件获取焦点并将其文本选中
        /// </summary>
        /// <param name="clientId">要获取焦点的控件ID</param>
        public void Select(string clientId)
        {
            this.ExecClientScript("document.getElementById(\"" + clientId + "\").select();");
        }
        #endregion

        #region 向客户端弹出一个对话框
        /// <summary>
        /// 向客户端弹出一个对话框
        /// </summary>
        /// <param name="message">对话框中显示的消息</param>
        public void MessageBox(string message)
        {
            this.ExecClientScript("alert(\"" + this.FilterString(message) + "\");");
        }
        #endregion

        #region 向客户端弹出DIV层
        /// <summary>
        /// 向客户端弹出DIV层
        /// </summary>
        /// <param name="url">页面</param>
        /// <param name="title">页面标题</param>
        /// <param name="id">页面ID</param>
        /// <param name="width">页面的宽</param>
        /// <param name="height">页面的高</param>
        public void Dialog(string url, string title, string id, int width, int height)
        {
            this.ExecClientScript("Dialog('" + url + "','" + title + "','" + id + "'," + width + "," + height + ");");
        }
        #endregion

        #region 从本页面跳转到相应的页面
        /// <summary>
        /// 从本页面跳转到相应的页面
        /// </summary>
        /// <param name="url">要跳转到得页面地址</param>
        public void Redirect(string url)
        {
            if (this.IsLplPostBack)
            {
                this.ExecClientScript("location.href = \"" + FilterString(url) + "\"");
            }
            else
            {
                this.page.Response.Redirect(url);
            }
        }
        #endregion

        #region 过滤字符串
        /// <summary>
        /// 过滤字符串
        /// </summary>
        /// <param name="value">要过滤的字符串</param>
        /// <returns>返回过滤过的字符串</returns>
        private string FilterString(string value)
        {
            if (value == null)
            {
                return "";
            }
            return value.Replace(@"\", @"\\").Replace("\"", "\\\"").Replace("\r", @"\r").Replace("\n", @"\n");
        }
        #endregion

        #region 获取缓存中的数据
        /// <summary>
        /// 获取缓存中的数据
        /// </summary>
        /// <param name="key">缓存的键</param>
        /// <returns>返回缓存中的数据</returns>
        public object GetCache(string key)
        {
            return this.page.Cache.Get(key);
        }
        #endregion

        #region 设置缓存
        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">缓存的键</param>
        /// <param name="value">要放进缓存中的值</param>
        public void SetCache(string key, object value)
        {
            this.page.Cache.Insert(key, value, null, DateTime.Now.AddMinutes(Convert.ToDouble(this.page.Session.Timeout)), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
        }
        #endregion

        #region 移除缓存
        /// <summary>
        /// 移除缓存
        /// </summary>
        /// <param name="key">要移除缓存的键</param>
        public void RemoveCache(string key)
        {
            this.page.Cache.Remove(key);
        }
        #endregion

        #region 获取页面唯一标示
        /// <summary>
        /// <para>获取页面的唯一标示</para>
        /// <para>由页面的虚拟路径+IP地址+DNS名称</para>
        /// </summary>
        /// <returns>一个页面唯一标示</returns>
        public string GetPageGuid()
        {
            return this.page.Request.FilePath + this.page.Request.UserHostAddress + this.page.Request.UserHostName;
        }
        #endregion

        #region 获取页面的文件名称
        /// <summary>
        /// 获取页面文件名称
        /// </summary>
        /// <returns>页面的文件名称</returns>
        public string GetPageFileName()
        {
            string url = this.page.Request.FilePath.ToString();
            return url.Substring(url.LastIndexOf("/") + 1);
        }
        #endregion

        #region 向客户端注册脚本
        /// <summary>
        /// 向客户端注册脚本
        /// </summary>
        /// <param name="script"></param>
        public void RegisterScriptToClient(string script)
        {
            clientScriptCount++;
            System.Web.UI.Page page = HttpContext.Current.Handler as System.Web.UI.Page;
            if (!page.ClientScript.IsStartupScriptRegistered(page.GetType(), "clientScript" + clientScriptCount))
                page.ClientScript.RegisterStartupScript(page.GetType(), "clientScript" + clientScriptCount, script);
        }
        #endregion

        #region 请求处理
        /// <summary>
        /// 请求处理
        /// </summary>
        public void HandleRequest()
        {
            string LiPuLiangAction = this.page.Request["LiPuLiangAction"];
            if (LiPuLiangAction == null)
            {
                string GetLPLClientScript = this.page.Request["GetLPLClientScript"];
                if (GetLPLClientScript == null)
                {
                    this.RegisterScriptToClient("<script type=\"text/javascript\" src=\"" + this.GetPageFileName() + "?GetLPLClientScript=GetLPLClientScript\"></script>");
                }
                else
                {
                    if (GetLPLClientScript == "GetLPLClientScript")
                    {
                        this.page.Response.Clear();
                        this.page.Response.ContentType = "application/text";
                        this.page.Response.Write(Resource.GetLPLClientScript + this.GetCache("____client__" + this.GetPageGuid()));
                        this.page.Response.End();
                    }
                }
                string GetLPLPublicClientScript = this.page.Request["GetLPLPublicClientScript"];
                if (GetLPLPublicClientScript == null)
                {
                    this.RegisterScriptToClient("<script type=\"text/javascript\" src=\"" + this.GetPageFileName() + "?GetLPLPublicClientScript=GetLPLPublicClientScript\"></script>");
                }
                else
                {
                    if (GetLPLPublicClientScript == "GetLPLPublicClientScript")
                    {
                        this.page.Response.Clear();
                        this.page.Response.ContentType = "application/text";
                        this.page.Response.Write(Resource.GetLPLPublicClientScript.Replace("{src}", this.page.ClientScript.GetWebResourceUrl(base.GetType(), "YhmOA.Common.page.edtError.png")));
                        this.page.Response.End();
                    }
                }
            }
            else
            {
                if (LiPuLiangAction == "CallServerFunction")
                {
                    string FunctionName = this.page.Request["FunctionName"];
                    if (FunctionName.Trim() != "")
                    {
                        string Parameters = this.page.Request["Parameters"];
                        this.ServerMessageList.Add(new ServerMessage(ServerMessageType.Return, this.InvokeMethod(FunctionName, Parameters)));
                    }
                }
            }
        }
        #endregion

        #region 向客户端输出事件
        /// <summary>
        /// 向客户端输出事件
        /// </summary>
        public void Render()
        {
            string LiPuLiangAction = this.page.Request["LiPuLiangAction"];
            if (LiPuLiangAction != null && LiPuLiangAction == "CallServerFunction")
            {
                string lplAjax = this.page.Request["__LPLAJAX"];
                if (lplAjax != null && lplAjax == "true")
                {
                    ControlCollection controls = this.page.Form.Controls;
                    foreach (Control control in controls)
                    {
                        WebControl wc = control as WebControl;
                        if (wc != null)
                        {
                            if ((wc.Attributes["notAjaxRender"] ?? "") == "")
                            {
                                ControlReaderToServerMessage(wc);
                            }
                        }
                    }
                    this.ExecClientScript("____Validation();");
                    StringBuilder builder = new StringBuilder("--BEGIN--[{\"type\":\"\",\"id\":\"\",\"context\":\"\"}");
                    foreach (ServerMessage serverMessage in this.ServerMessageList)
                    {
                        builder.Append(",");
                        builder.Append(serverMessage.ToString());
                    }
                    builder.Append("]--END--");
                    this.page.Response.Clear();
                    this.page.Response.ContentType = "application/text";
                    this.page.Response.Write(EnCode(builder.ToString()));
                    this.page.Response.End();
                }
            }
        }
        #endregion

        #region 执行方法
        /// <summary>
        /// 执行方法
        /// </summary>
        /// <param name="methodName">要执行的方法名</param>
        /// <param name="parameters">方法的参数</param>
        /// <returns>方法的返回值</returns>
        public string InvokeMethod(string methodName, string parameters)
        {
            object[] param = null;
            if (parameters != null && parameters.Trim() != "")
            {
                param = parameters.Split(',');
                for (int i = 0; i < param.Length; i++)
                {
                    param[i] = this.DeCode(param[i].ToString());
                }
            }
            return new DataConvert(this.page.GetType().GetMethod(methodName).Invoke(this.page, param), this.responseType).ToString();
        }
        #endregion

        #region 编码
        /// <summary>
        /// 编码
        /// </summary>
        /// <param name="value">要编码的字符串</param>
        /// <returns>编码后的字符串</returns>
        public string EnCode(string value)
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                byte[] ba = Encoding.Unicode.GetBytes(value);
                for (int i = 0; i < ba.Length; i += 2)
                {
                    sb.Append("%u");
                    sb.Append(ba[i + 1].ToString("X2"));
                    sb.Append(ba[i].ToString("X2"));
                }
                return sb.ToString();
            }
            catch
            {
                return null;
            }
        }
        #endregion

        #region 解码
        /// <summary>
        /// 解码
        /// </summary>
        /// <param name="value">要解码的字符串</param>
        /// <returns>解码后的字符串</returns>
        public string DeCode(string value)
        {
            try
            {
                return HttpUtility.UrlDecode(value);
            }
            catch
            {
                return null;
            }
        }
        #endregion

        #region 将控件信息加入到ServerMessageList集合中去
        /// <summary>
        /// 将控件信息加入到ServerMessageList集合中去
        /// </summary>
        /// <param name="control">要放进去的控件</param>
        public void ControlReaderToServerMessage(Control control)
        {
            this.ServerMessageList.Insert(0,new ServerMessage(ServerMessageType.Control, control.ClientID, ControlRenderToString(control)));
        }
        #endregion

        #region 返回控件在客户端生成的代码
        /// <summary>
        /// 返回控件在客户端生成的代码
        /// </summary>
        /// <param name="control">要返回客户端代码的控件</param>
        /// <returns>控件在客户端生成的代码</returns>
        public string ControlRenderToString(Control control)
        {
            StringWriter writer = new StringWriter();
            HtmlTextWriter htmlTextWriter = new HtmlTextWriter(writer);
            control.RenderControl(htmlTextWriter);
            return writer.GetStringBuilder().ToString();
        }
        #endregion

        #region 是否是回发
        /// <summary>
        /// 是否是回发
        /// </summary>
        public bool IsLplPostBack
        {
            get
            {
                bool flag = false;
                if (HttpContext.Current.Request["LiPuLiangAction"] == "CallServerFunction")
                {
                    flag = true;
                }
                else
                {
                    flag = this.page.IsPostBack;
                }
                return flag;
            }
        }
        #endregion
    }
    #endregion

    #region 页面输出类型--枚举
    /// <summary>
    /// 页面输出类型:text or json
    /// </summary>
    public enum ResponseType
    { 
        /// <summary>
        /// 输出类型为文本数据
        /// </summary>
        text,
        /// <summary>
        /// 输出文本为json数据
        /// </summary>
        json
    }
    #endregion
}
